#define THREAD_QUANTA 5

// Saves the value of esp to var
#define STORE_ESP(var)  asm("movl %%esp, %0;" : "=r" ( var ))
#define STORE_EBP(var)  asm("movl %%ebp, %0;" : "=r" ( var ))
// Loads the contents of var into esp
#define LOAD_ESP(var)   asm("movl %0, %%esp;" : : "r" ( var ))
#define LOAD_EBP(var)   asm("movl %0, %%ebp;" : : "r" ( var ))
// Calls the function func
#define CALL(addr)              asm("call *%0;" : : "r" ( addr ))

// Pushes the contents of var to the stack
#define PUSH(var)               asm("movl %0, %%edi; push %%edi;" : : "r" ( var ))

/* Possible states of a thread; */
typedef enum  {T_FREE, T_RUNNING, T_RUNNABLE, T_SLEEPING} uthread_state;

#define STACK_SIZE  4096
#define MAX_THREAD  64
#define MAX_UTHREADS MAX_THREAD
typedef struct uthread uthread_t, *uthread_p;

struct uthread {
	int				tid;
	int 	       	esp;        /* current stack pointer */
	int 	       	ebp;        /* current base pointer */
	char		   *stack;	    /* the thread's stack */
	uthread_state   state;     	/* running, runnable, sleeping */
	int wait_list[MAX_UTHREADS-1];
	int wait_count;
	
};


typedef enum  {sem_free,sem_locked} semaphore_state;

struct binary_semaphore
{
	struct uthreadqueue *queue;
	int numOfWaiting;
	semaphore_state flag;
};


void print_uthreads(void); 
void print_stack(int);
void uthread_init(void);
int  uthread_create(void (*func)(void *), void* value);
void uthread_exit(void);
void uthread_yield(void);
void uthread_sleep(void);
int  uthread_self(void);
int  uthread_join(int tid);
void binary_semaphore_init(struct binary_semaphore* semaphore, int value);
void binary_semaphore_down(struct binary_semaphore* semaphore); 
void binary_semaphore_up(struct binary_semaphore* semaphore);

